package com.nuoniu.sibanyun.service.check.impl;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nuoniu.sibanyun.common.exception.NuoNiuException;
import com.nuoniu.sibanyun.entity.bo.*;
import com.nuoniu.sibanyun.entity.check.VQualityCheckDetail;
import com.nuoniu.sibanyun.entity.check.VQualityCheckMain;
import com.nuoniu.sibanyun.entity.erp.ErpNumberSet;
import com.nuoniu.sibanyun.entity.erp.ErpVoucherTable;
import com.nuoniu.sibanyun.entity.inOut.VInOutRecordMain;
import com.nuoniu.sibanyun.entity.po.VPurchaseArrivalMain;
import com.nuoniu.sibanyun.entity.so.VSaleDeliveryMain;
import com.nuoniu.sibanyun.entity.so.VSaleOrderMain;
import com.nuoniu.sibanyun.mapper.check.VQualityCheckMainMapper;
import com.nuoniu.sibanyun.mapper.erp.ErpNumberSetMapper;
import com.nuoniu.sibanyun.service.check.IVQualityCheckDetailService;
import com.nuoniu.sibanyun.service.check.IVQualityCheckMainService;
import com.nuoniu.sibanyun.service.crm.ICrmGoodsService;
import com.nuoniu.sibanyun.service.erp.IErpAccountService;
import com.nuoniu.sibanyun.service.erp.IErpNumberSetService;
import com.nuoniu.sibanyun.service.erp.IErpVoucherDesignService;
import com.nuoniu.sibanyun.service.erp.IErpVoucherTableService;
import com.nuoniu.sibanyun.userThread.UserInfo;
import com.nuoniu.sibanyun.userThread.UserThreadLocal;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;

/**
 * <p>
 * 质检管理_主表 服务实现类
 * </p>
 *
 * @author 白强
 * @since 2021-07-14
 */
@Service
@Log4j2
public class VQualityCheckMainServiceImpl extends ServiceImpl<VQualityCheckMainMapper, VQualityCheckMain> implements IVQualityCheckMainService {

    @Autowired
    private IErpAccountService erpAccountService;
    @Autowired
    private IErpNumberSetService numberSetService;
    @Autowired
    private ErpNumberSetMapper numberSetMapper;
    @Autowired
    private IErpVoucherDesignService erpVoucherDesignService;
    @Autowired
    private IVQualityCheckDetailService qualityCheckDetailService;
    @Autowired
    private IErpVoucherTableService erpVoucherTableService;
    @Autowired
    private ICrmGoodsService crmGoodsService;

    //质检来源单据类型
    private static final String[]  qualityCheckSourceVoucherArr = {"PuArrival","ProductionFinish","DelegateArrival","ProductionWork"};

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void saveQualityCheckMain(VQualityCheckMain qualityCheckMain) {
        List<VQualityCheckDetail> orderDetailList = qualityCheckMain.getOrderDetailList();
        if(null == orderDetailList)throw new NuoNiuException("单据明细不能为空");
        Long mainId = qualityCheckMain.getId();
        UserInfo userInfo = UserThreadLocal.get();
        Integer currentAccountId = erpAccountService.getCurrentAccountId();
        VQualityCheckMain oldVQualityCheckMain = null;
        if(mainId == null) {
            String code = getCode();
            if(code == null) {
                    new NuoNiuException("单据编号已上限");
            }
            boolean isHaveId = orderDetailList.stream().anyMatch(f -> null != f.getId());
            if(isHaveId)throw new NuoNiuException("单据明细错误：不能新增已经存在的明细记录");
            qualityCheckMain.setAccountId(currentAccountId);
            qualityCheckMain.setVoucherCode(code);
            qualityCheckMain.setCompanyId(userInfo.getCompanyId());
            qualityCheckMain.setCreateUserId(userInfo.getUserId());
            qualityCheckMain.setCreateUserName(userInfo.getRealName());
            qualityCheckMain.setVoucherState(-1);
        }else {
            //校验详情（详情不能有其他单据的明细ID）
            boolean isHaveErrorId = orderDetailList.stream().anyMatch(f -> null != f.getOrderId() && !mainId.toString().equals(f.getOrderId().toString()));
            if(isHaveErrorId)throw new NuoNiuException("单据明细错误：不能修改其他单据的明细记录");
            oldVQualityCheckMain = getById(mainId);
            Integer voucherState = oldVQualityCheckMain.getVoucherState();
            if(null != voucherState && voucherState > 0){
                throw new NuoNiuException("已审核,不能修改");
            }
            /**************  修改权限 *******************/
            if(!crmGoodsService.isHaveOperationRight(oldVQualityCheckMain.getCreateUserId().longValue())){
                throw new NuoNiuException("你没有权限操作该记录");
            }

            qualityCheckMain.setAccountId(oldVQualityCheckMain.getAccountId());
            qualityCheckMain.setSourceVoucherCode(oldVQualityCheckMain.getSourceVoucherCode());
            qualityCheckMain.setSourceVoucherId(oldVQualityCheckMain.getSourceVoucherId());
            qualityCheckMain.setSourceVoucherType(oldVQualityCheckMain.getSourceVoucherType());
            qualityCheckMain.setSourceVoucherDate(oldVQualityCheckMain.getSourceVoucherDate());
        }
        qualityCheckMain.setCumExecuteQuantity(null);
        // 校验 明细数量
        boolean isOk = qualityCheckMain.getOrderDetailList().stream().anyMatch(f -> null == f.getBaseQuantity() || !(f.getBaseQuantity().compareTo(BigDecimal.ZERO) > 0));
        if(isOk)throw new NuoNiuException("明细数量必须大于0");
        //计算 明细物料 总数
        BigDecimal totalQuantity =  qualityCheckMain.getOrderDetailList().stream().map(VQualityCheckDetail::getBaseQuantity).reduce(BigDecimal.ZERO,BigDecimal::add);
        qualityCheckMain.setTotalQuantity(totalQuantity.abs());

        Boolean result = this.saveOrUpdate(qualityCheckMain);
        if(result) {
            List<Long> detailIds = new ArrayList<>();
            orderDetailList.forEach(p -> {
                p.setOrderId(qualityCheckMain.getId().intValue());
                p.setCompanyId(userInfo.getCompanyId());
                p.setAccountId(qualityCheckMain.getAccountId());
                p.setSourceVoucherId(qualityCheckMain.getSourceVoucherId());
                p.setSourceVoucherCode(qualityCheckMain.getSourceVoucherCode());
                p.setSourceVoucherType(qualityCheckMain.getSourceVoucherType());
                p.setSourceVoucherDate(qualityCheckMain.getSourceVoucherDate());
                if(p.getId() != null) {
                    detailIds.add(p.getId());
                }
            });

            boolean isDealDelete = false;
            if (null != mainId){
                //删除明细
                QueryWrapper wrapper = new QueryWrapper();
                wrapper.eq("order_id", mainId);
                if(detailIds != null && detailIds.size() > 0) {
                    wrapper.notIn("id", detailIds);
                }
                isDealDelete = qualityCheckDetailService.remove(wrapper);
            }


            // *** 如果 来源订单不为空,校验
            if(null != qualityCheckMain.getSourceVoucherId()){
                if(isDealDelete)throw new NuoNiuException("有来源的单据不能删除明细");
                List<String> qualityCheckSourceVoucher = Arrays.asList(qualityCheckSourceVoucherArr);
                if(!qualityCheckSourceVoucher.contains(qualityCheckMain.getSourceVoucherType()))throw new NuoNiuException("检验单的来源单，只能是采购到货单、委外到货单、生产完工单和生产加工单");
                List<VQualityCheckDetail> oldOrderDetailList = null;
                HashMap<Long,VQualityCheckDetail> oldOrderListMap = new HashMap<>();
                // 如果是 修改
                if( null != mainId){
                    //查询 当前 质检 明细
                    oldOrderDetailList = qualityCheckDetailService.listByMainId(mainId);
                    oldOrderDetailList.forEach(detail -> oldOrderListMap.put(detail.getId(),detail));
                }
                /*******更新累计送检数量***********/
                QualityCheckSourceBo qualityCheckSourceBo = new QualityCheckSourceBo();
                qualityCheckSourceBo.setCalculateType(1);
                qualityCheckSourceBo.setSourceVoucherId(qualityCheckMain.getSourceVoucherId());
                qualityCheckSourceBo.setSourceVoucherType(qualityCheckMain.getSourceVoucherType());
                List<QualityCheckSourceDetailBo> detailBoList = new ArrayList<>();
                qualityCheckSourceBo.setDetailBoList(detailBoList);
                orderDetailList.forEach(detail->{

                    QualityCheckSourceDetailBo qualityCheckSourceDetailBo = new QualityCheckSourceDetailBo();
                    qualityCheckSourceDetailBo.setBaseQuantity(detail.getBaseQuantity());
                    qualityCheckSourceDetailBo.setInventoryId(detail.getInventoryId());
                    qualityCheckSourceDetailBo.setInventoryName(detail.getInventoryName());
                    qualityCheckSourceDetailBo.setOrderId(detail.getOrderId());
                    qualityCheckSourceDetailBo.setSourceDetailId(detail.getSourceDetailId());
                    //如果 修改以前的明细数据
                    if( null != detail.getId()){
                        VQualityCheckDetail oldQualityCheckDetail = oldOrderListMap.get(detail.getId());
                        if(null != oldQualityCheckDetail){
                            BigDecimal offset = detail.getBaseQuantity().subtract(oldQualityCheckDetail.getBaseQuantity());
                            if(offset.compareTo(BigDecimal.ZERO) == 0)return;
                            qualityCheckSourceDetailBo.setBaseQuantity(offset);
                        }
                    }
                    detailBoList.add(qualityCheckSourceDetailBo);
                });

                calculateQualityCheck(qualityCheckSourceBo);
            }

            //保存单据明细表
            qualityCheckDetailService.saveOrUpdateBatch(orderDetailList);
        }
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void delete(Long id) {
        UserInfo userInfo = UserThreadLocal.get();
        VQualityCheckMain qualityCheckMain = getById(id);
        if(qualityCheckMain == null) {
            throw new NuoNiuException("此单据不存在");
        }
        /**************  修改权限 *******************/
        if(!crmGoodsService.isHaveOperationRight(qualityCheckMain.getCreateUserId().longValue())){
            throw new NuoNiuException("你没有权限操作该记录");
        }
        /*******更新累计送检数量***********/
        QualityCheckSourceBo qualityCheckSourceBo = new QualityCheckSourceBo();
        qualityCheckSourceBo.setCalculateType(2);
        qualityCheckSourceBo.setSourceVoucherId(qualityCheckMain.getSourceVoucherId());
        qualityCheckSourceBo.setSourceVoucherType(qualityCheckMain.getSourceVoucherType());
        List<QualityCheckSourceDetailBo> detailBoList = new ArrayList<>();
        qualityCheckSourceBo.setDetailBoList(detailBoList);
        List<VQualityCheckDetail> orderDetailList = qualityCheckDetailService.listByMainId(id);
        orderDetailList.forEach(detail->{
            QualityCheckSourceDetailBo qualityCheckSourceDetailBo = new QualityCheckSourceDetailBo();
            qualityCheckSourceDetailBo.setBaseQuantity(detail.getBaseQuantity());
            qualityCheckSourceDetailBo.setInventoryId(detail.getInventoryId());
            qualityCheckSourceDetailBo.setInventoryName(detail.getInventoryName());
            qualityCheckSourceDetailBo.setOrderId(detail.getOrderId());
            qualityCheckSourceDetailBo.setSourceDetailId(detail.getSourceDetailId());
            detailBoList.add(qualityCheckSourceDetailBo);
        });

        calculateQualityCheck(qualityCheckSourceBo);
        removeById(id);
    }

    @Override
    public String getCode() {
        UserInfo userInfo = UserThreadLocal.get();
        Integer currentAccountId = erpAccountService.getCurrentAccountId();
        Integer companyId = userInfo.getCompanyId();
        ErpNumberSet numberSet = numberSetMapper.getByCode("QualityCheck", companyId, currentAccountId);
        String dateStr = numberSet.getMedian() == 1 ? "%Y-%m-%d" : "%Y-%m";
        String code = baseMapper.getNewestCode(companyId, dateStr);
        return numberSetService.getCode(numberSet, code);
    }

    @Override
    public void submit(Long id, Integer status) {
        if(null == id || null == status || (status > 0 || status < -1 ))throw new NuoNiuException("参数错误");
        VQualityCheckMain qualityCheckMain = this.getById(id);
        if( null == id)throw new NuoNiuException("记录不存在");
        //校验状态
        Integer voucherState = qualityCheckMain.getVoucherState();
        if(status == 0){
            if (voucherState > -1) throw new NuoNiuException("该单据已经提交");
        }else if(status == -1){
            if (voucherState > 0) throw new NuoNiuException("该单据已经审核,请先弃审");
        }
        //提交
        qualityCheckMain.setVoucherState(status);
        this.updateById(qualityCheckMain);
    }
    @Override
    public void examine(Long id, Integer status) {
        if (!(0 == status || 1 == status))throw new NuoNiuException("参数错误");
        UserInfo userInfo = UserThreadLocal.get();
        VQualityCheckMain qualityCheckMain = getById(id);
        if (null == qualityCheckMain)throw new NuoNiuException("参数错误");
        Integer voucherState = qualityCheckMain.getVoucherState();
        if(  voucherState > 1 )throw new NuoNiuException("已经关闭，不能做审核操作");
        if( 0  == voucherState && 0 == status)throw new NuoNiuException("未审核，不能做弃审操作");
        if( 1  == voucherState && 1 == status)throw new NuoNiuException("已审核，不能做审核操作");

        qualityCheckMain.setVoucherState(status);
        qualityCheckMain.setReviewerDate(LocalDate.now());
        qualityCheckMain.setReviewerUserId(userInfo.getUserId());
        qualityCheckMain.setReviewerUserName(userInfo.getRealName());
        updateById(qualityCheckMain);
    }

    @Override
    public void calculateQualityCheck(QualityCheckSourceBo qualityCheckSourceBo) {
        UserInfo userInfo = UserThreadLocal.get();
        Integer currentAccountId = erpAccountService.getCurrentAccountId();
        Integer companyId = userInfo.getCompanyId();
        Integer calculateType = qualityCheckSourceBo.getCalculateType();
        String sourceVoucherType = qualityCheckSourceBo.getSourceVoucherType();
        Integer sourceVoucherId = qualityCheckSourceBo.getSourceVoucherId();
        //查询 来源单据 对应 表名
        ErpVoucherTable erpVoucherTable = erpVoucherTableService.getErpVoucherTable(sourceVoucherType);
        String tableName = erpVoucherTable.getTableName();
        String detailTableName = erpVoucherTable.getDetailTableName();
        //查询 来源单据 主表
        QualityCheckSourceDataBo qualityCheckSourceDataBo = baseMapper.getVoucherMainBoById(tableName, companyId, currentAccountId, sourceVoucherId);
        if(null == qualityCheckSourceDataBo)throw new NuoNiuException("单据明细校验错误：查询不到来源单据");
        //1.判断 来源单据状态
        Integer sourceState = qualityCheckSourceDataBo.getVoucherState();
        if( 0 == sourceState && 1 == calculateType)throw new NuoNiuException("单据明细校验错误：来源单据未审核,不能生单");
//        if(10 == sourceState && 1 == voucherSearchBo.getCalculateType())throw new NuoNiuException("校验累计退货情况：来源单据已经关闭");
        //查询 来源单据 明细
        List<QualityCheckSourceDataDetailBo> qualityCheckSourceDataDetailBoList = baseMapper.getVoucherDetailBoById(detailTableName, companyId, currentAccountId, sourceVoucherId);
        //2.校验 明细数量 是否超标
        Map<String,QualityCheckSourceDataDetailBo> sourceDetailMap = new HashMap<>();
        qualityCheckSourceDataDetailBoList.forEach(detail-> sourceDetailMap.put(detail.getInventoryId() +"_"+ detail.getId(), detail));
        /** 需要更新的 来源明细单据 */
        List<QualityCheckSourceDataDetailBo> editVoucherDetailBoList = new ArrayList<>();
        /** 来源单据 主表  信息 */
        BigDecimal totalQuantity = qualityCheckSourceDataBo.getTotalQuantity();
        BigDecimal cumQualityCheckQuantity = qualityCheckSourceDataBo.getCumQualityCheckQuantity();


        List<QualityCheckSourceDetailBo> detailBoList = qualityCheckSourceBo.getDetailBoList();
        for (QualityCheckSourceDetailBo detailBo:detailBoList) {
            QualityCheckSourceDataDetailBo sourceDetail = sourceDetailMap.get(detailBo.getInventoryId() +"_"+ detailBo.getSourceDetailId());
            if( null == sourceDetail )throw new NuoNiuException("单据明细校验错误:在来源单据明细中，查询不到："+ detailBo.getInventoryName() + " 的物料");
            /** 质检明细  送检数量 */
            BigDecimal baseQuantity = detailBo.getBaseQuantity();
            /** 来源明细  信息 */
            BigDecimal sourceDetailBaseQuantity = sourceDetail.getBaseQuantity();
            BigDecimal detailCumQualityCheckQuantity = sourceDetail.getCumQualityCheckQuantity();
            if (null ==  detailCumQualityCheckQuantity)detailCumQualityCheckQuantity = new BigDecimal(0);
            //1.新增
            if (1 == calculateType){
                // 先计算误差
                BigDecimal subtract = baseQuantity.subtract(detailBo.getLastBaseQuantity());
                //相加 过后的累计
                BigDecimal newDetailCumQualityCheckQuantity = subtract.add(detailCumQualityCheckQuantity);
                BigDecimal residueQuantity = sourceDetailBaseQuantity.subtract(newDetailCumQualityCheckQuantity);
                BigDecimal realResidueQuantity = sourceDetailBaseQuantity.subtract(detailCumQualityCheckQuantity);
                if (residueQuantity.compareTo(BigDecimal.ZERO) < 0)throw new NuoNiuException("单据明细校验错误:在来源单据明细中，查"+ detailBo.getInventoryName() + " 的物料的累计送检数量已经超出范围(剩余：" + realResidueQuantity + ")");
                QualityCheckSourceDataDetailBo qualityCheckSourceDataDetailBo = new QualityCheckSourceDataDetailBo();
                qualityCheckSourceDataDetailBo.setId(detailBo.getSourceDetailId().longValue());
                qualityCheckSourceDataDetailBo.setOrderId(qualityCheckSourceDataBo.getId().intValue());
                qualityCheckSourceDataDetailBo.setCumQualityCheckQuantity(newDetailCumQualityCheckQuantity);
                editVoucherDetailBoList.add(qualityCheckSourceDataDetailBo);
                cumQualityCheckQuantity = cumQualityCheckQuantity.add(subtract);
            }else if(2 == calculateType){
                //相加 过后的累计
                BigDecimal newDetailCumQualityCheckQuantity = detailCumQualityCheckQuantity.subtract(baseQuantity);
                if (newDetailCumQualityCheckQuantity.compareTo(BigDecimal.ZERO) < 0 ) {
                    log.info("累计送检数量校验：删除时，原单据明细累计为负数了，直接置为0");
                    newDetailCumQualityCheckQuantity = BigDecimal.ZERO;
                }
                QualityCheckSourceDataDetailBo qualityCheckSourceDataDetailBo = new QualityCheckSourceDataDetailBo();
                qualityCheckSourceDataDetailBo.setId(detailBo.getSourceDetailId().longValue());
                qualityCheckSourceDataDetailBo.setOrderId(qualityCheckSourceDataBo.getId().intValue());
                qualityCheckSourceDataDetailBo.setCumQualityCheckQuantity(newDetailCumQualityCheckQuantity);
                editVoucherDetailBoList.add(qualityCheckSourceDataDetailBo);
                cumQualityCheckQuantity = cumQualityCheckQuantity.subtract(baseQuantity);
            }
        }

        qualityCheckSourceDataBo.setCumQualityCheckQuantity(cumQualityCheckQuantity);
        if ( editVoucherDetailBoList.size() > 0){
            baseMapper.updateQualityCheckSourceDataBo(tableName, qualityCheckSourceDataBo);
            baseMapper.updateQualityCheckSourceDataDetailBo(detailTableName,companyId,currentAccountId,editVoucherDetailBoList);
        }
    }
}
